﻿using System;
using System.Data;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Estimate.Common.Repository;
using Estimate.Common.Entity;
using Estimate.Common.DBFieldTypes;
using Estimate.Common.Estimate;
//using log4net;

namespace Estimate.Common.DBHealth
{
    /// <summary>
    /// 检测预报表的问题
    /// </summary>
    public abstract class BaseForeHealth
    {

        static ForeSpanType[] ShortSpans = new ForeSpanType[]{
                                                    ForeSpanType.FD00_12,  ForeSpanType.FD00_24,  ForeSpanType.FD12_24, 
                                                    ForeSpanType.FD24_36,  ForeSpanType.FD24_48,  ForeSpanType.FD36_48, 
                                                    ForeSpanType.FD48_60,  ForeSpanType.FD48_72,  ForeSpanType.FD60_72
                                                  };
        static ForeSpanType[] MiddleSpans = new ForeSpanType[]{
                                                     
                                                    ForeSpanType.FD72_84,  ForeSpanType.FD72_96,  ForeSpanType.FD84_96,
                                                    ForeSpanType.FD96_108, ForeSpanType.FD96_120, ForeSpanType.FD108_120, 
                                                    ForeSpanType.FD120_132,ForeSpanType.FD120_144,ForeSpanType.FD132_144, 
                                                    ForeSpanType.FD144_156,ForeSpanType.FD144_168,ForeSpanType.FD156_168
                                                  };
        static ForeSpanType[] Short24Spans = new ForeSpanType[] { ForeSpanType.FD00_24, ForeSpanType.FD24_48, ForeSpanType.FD48_72 };
        static ForeSpanType[] Middle24Spans = new ForeSpanType[] { ForeSpanType.FD72_96, ForeSpanType.FD96_120, ForeSpanType.FD120_144, ForeSpanType.FD144_168 };

        static ForeSendpointType[] ShortSendpoints = new ForeSendpointType[] { ForeSendpointType.H05, ForeSendpointType.H06, ForeSendpointType.H10, ForeSendpointType.H16 };
        static ForeSendpointType[] MiddleSendpoints = new ForeSendpointType[] { ForeSendpointType.H06, ForeSendpointType.H10, ForeSendpointType.H16 };

        static ForeFactorType[] ForeFactors = new ForeFactorType[] { ForeFactorType.wth };

        static List<string> WthCheckKeys = new List<string>(72);
        static List<string> TempCheckKeys = new List<string>(24);
         * 
        protected ForeRepository _repository;

        private Dictionary<string,int> _autoStations;

        private Dictionary<string, int> _manualStations;

        //public static ILog Logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        public static ForeSpanType[] spanArray = new ForeSpanType[] { ForeSpanType.FD00_24, ForeSpanType.FD24_48, ForeSpanType.FD48_72, ForeSpanType.FD72_96, ForeSpanType.FD96_120 };

        public BaseForeHealth(ForeRepository repository)
        {
            _repository = repository;
            _autoStations = new Dictionary<string, int>();
            _manualStations = new Dictionary<string, int>();
        }

        public abstract ForeSendpointType[] GetSendpointArray();

        public abstract RealStationCompareType GetCompareType(ForeSemiType semitype);

        protected virtual void ResetSemiStations(ForeSemiType semitype)
        {
            RealStationCompareRepository repository = new RealStationCompareRepository(_repository.ConnectionString);

            Dictionary<string, int> stations;
            if (semitype == ForeSemiType.Auto)
            {
                stations = _autoStations;
            }
            else
            {
                stations = _manualStations;
            }

            
            if (stations.Count == 0)
            {
                ForeRealStationCompareEntity[] entitys = repository.GetAllRecord(GetCompareType(semitype));
                foreach (ForeRealStationCompareEntity entity in entitys)
                {
                    stations[entity.ForeStation] = 0;
                }
            }
            else
            {
                Dictionary<string, int> newStations = new Dictionary<string, int>();
                foreach (string key in stations.Keys)
                {
                    newStations[key] = 0;
                }

                if (semitype == ForeSemiType.Auto)
                {
                    _autoStations = newStations;
                }
                else
                {
                    _manualStations = newStations;
                }
            }
        }

        public DataTable CheckHealth(DateTime beginDate, DateTime endDate)
        {

            DataTable CheckResult = new DataTable();
            CheckResult.Columns.Add("msg");
            CheckResult.Columns.Add("date");
            CheckResult.Columns.Add("factortype");
            CheckResult.Columns.Add("semitype");
            CheckResult.Columns.Add("sendpoint");
            CheckResult.Columns.Add("span");
            CheckResult.DefaultView.Sort = "msg asc,date asc,span asc";

            RealDataLogRepository realDataLogRepository = new RealDataLogRepository(_repository.ConnectionString);
            
            SendpointToClock parser = new SendpointToClock();
            
            ForeFactorType[] factorArray = new ForeFactorType[] { ForeFactorType.maxt, ForeFactorType.mint, ForeFactorType.wth};
            ForeSemiType[] semitypeArray = new ForeSemiType[] { ForeSemiType.Auto, ForeSemiType.Manual };

            DateTime cur = beginDate;
            while (cur <= endDate)
            {
                //先取出H06, H10, H16三个发报时刻的降水数据
                ForeSendpointType[] sendpoints = this.GetSendpointArray();
                ForeClockType[] clocks = parser.GetClockArrayWithSendPointArray(sendpoints);

                foreach(ForeSemiType semitype in semitypeArray)
                {                    
                    foreach(ForeFactorType factor in factorArray)
                    {
                        foreach (ForeSpanType span in spanArray)
                        {
                            DateTime realDate = cur.AddDays(GetPastDay(span));
                            if (!realDataLogRepository.IsRealDataExist(semitype, realDate))
                            {
                                CheckResult.Rows.Add(new object[] { "无实况数据", realDate.ToString("yyyy-MM-dd"), null, null, null, span.ToString() });
                                //msg.Add(string.Format("{0} {1} {2} 没有实况数据入库，无需检查相应的记录。跳过！", realDate.ToString("yyyy-MM-dd"), semitype,span));
                                continue;
                            }
                            
                            ForeEntity[] entities = _repository.InquerySemiWithDateRange(cur, cur, clocks, span, sendpoints, factor, semitype,false);
                            if( entities.Length != sendpoints.Length)
                            {
                                foreach(ForeSendpointType s in sendpoints)
                                {
                                    bool has = false;
                                    foreach(ForeEntity entity in entities)
                                    {
                                        if( s == entity.Sendpoint)
                                        {
                                            has = true;
                                            break;
                                        }
                                    }
                                    if( has == false)
                                        CheckResult.Rows.Add(new object[] { "缺少记录", cur.ToString("yyyy-MM-dd"), factor, semitype, s, span });                                       
                                }
                            }

                            foreach (ForeEntity entity in entities)
                            {
                                if (entity.Semi.Length <= 5)
                                {
                                    CheckResult.Rows.Add(new object[] { "空semi", entity.Date.ToString("yyyy-MM-dd"), entity.Type, entity.Semitype, entity.Sendpoint, entity.Span });
                                    
                                    //Logger.Error(FormatInfo("发现semi为空的记录", entity));                                     
                                }
                                else
                                {
                                    ResetSemiStations(entity.Semitype);

                                    CheckValue("value", entity.Value, entity, CheckResult);
                                    //semi是不会丢站的。因为semi中预先多存了
                                    CheckValue("semi", entity.Semi, entity, CheckResult);
                                }
                            }
                        }
                    }
                }
                cur = cur.AddDays(1);
            }

            return CheckResult;
        }

        private void CheckStations(ForeSemiType foreSemiType, out List<string> more, out List<string> miss)
        {
            more = new List<string>();
            miss = new List<string>();

            Dictionary<string, int> stations;
            if (foreSemiType == ForeSemiType.Auto)
            {
                stations = _autoStations;
            }
            else
            {
                stations = _manualStations;
            }

            foreach(KeyValuePair<string,int> pair in stations)
            {
                if( pair.Value == 0)
                    miss.Add( pair.Key);
                
                if( pair.Value > 1)
                    more.Add( pair.Key);
            }

            Dictionary<string, int> newStations = new Dictionary<string, int>();
            foreach (string key in stations.Keys)
            {
                newStations[key] = 0;
            }

            if (foreSemiType == ForeSemiType.Auto)
            {
                _autoStations = newStations;
            }
            else
            {
                _manualStations = newStations;
            }
        }

        private bool FindStation(ForeSemiType foreSemiType, string station,string name)
        {
            bool result = true;

            Dictionary<string, int> stations;
            if (foreSemiType == ForeSemiType.Auto)
            {
                stations = _autoStations;
            }
            else
            {
                stations = _manualStations;
            }

            if (stations.ContainsKey(station))
                stations[station] += 1;
            else
            {
                result = false;       
            }
            return result;
        }

        public bool CheckValue(string name, string value, ForeEntity entity,DataTable CheckResult)
        {
            bool result = true;

            string[] ss = Regex.Split(value, @"\|", RegexOptions.IgnoreCase);
            foreach (string s in ss)
            {
                if (s.Length < 5)
                    continue;
                string station = s.Substring(0, 5);
                bool r = FindStation(entity.Semitype, station,name);
                if (r == false)
                {
                    CheckResult.Rows.Add(new object[] { string.Format("{0}中出现非常站点{1}", name, station), entity.Date.ToString("yyyy-MM-dd"), entity.Type, entity.Semitype, entity.Sendpoint, entity.Span });
                    //Logger.Error(FormatInfo(string.Format("{0}中出现非常站点{1}", name, station), entity));   
                }
            }
            List<string> more;
            List<string> miss;
            CheckStations(entity.Semitype, out more, out miss);
            if (more.Count > 0)
            {
                result = false;

                string r = string.Join(",", more);
                CheckResult.Rows.Add(new object[] { string.Format("{0}中多次出现站号为{1}的记录", name, r), entity.Date.ToString("yyyy-MM-dd"), entity.Type, entity.Semitype, entity.Sendpoint, entity.Span });
                //Logger.Error(FormatInfo(string.Format("{0}中多次出现站号为{1}的记录", name, r), entity));  
            }

            if (miss.Count > 0)
            {
                result = false;

                string r = string.Join(",", miss);
                CheckResult.Rows.Add(new object[] { string.Format("{0} 丢失站 {1}", name, r), entity.Date.ToString("yyyy-MM-dd"), entity.Type, entity.Semitype, entity.Sendpoint, entity.Span });
                //Logger.Error(FormatInfo(string.Format("{0} 丢失站 {1}", name, r), entity));                
            }            

            return result;
        }

        public int GetPastDay(ForeSpanType span)
        {
            int result;

            string[] hours = span.ToString().Substring(2).Split('_');
            int start = Convert.ToInt32(hours[0]);
            int end = Convert.ToInt32(hours[1]);

            if ((end - start) == 12)
            {
                if ((end % 24) == 0)
                {//是后12小时的
                    result = end / 24;
                }
                else
                {
                    result = start / 24 + 1;
                }
            }
            else
            {
                result = end / 24;
            }

            return result;
        }

        //private string FormatInfo(string message, ForeEntity entity)
        //{
        //    return string.Format("{0}, date='{1}' and type='{2}' and semitype='{3}' and sendpoint='{4}' and span='{5}' ", message, entity.Date.ToString("yyyyMMdd"), entity.Type, entity.Semitype, entity.Sendpoint, entity.Span);
        //}
         
       
    }
}
